#include <unistd.h>
#include "ALooperRoster.h"
#include "AHandler.h"
#include "AMessage.h"

ALooperRoster::ALooperRoster()
    : mNextHandlerID(1) {
}

ALooper::handler_id ALooperRoster::registerHandler(
        const std::shared_ptr<ALooper> &looper, const std::shared_ptr<AHandler> &handler) {

    std::lock_guard<std::mutex> _lock(mLock);

    if (handler->id() != 0) {
        printf("A handler must only be registered once.");
        return -1;
    }

    HandlerInfo info;
    info.mLooper = looper;
    info.mHandler = handler;
    ALooper::handler_id handlerID = mNextHandlerID++;
    mHandlers[handlerID] = info;

    handler->setID(handlerID, looper);

    return handlerID;
}

void ALooperRoster::unregisterHandler(ALooper::handler_id handlerID) {
    std::lock_guard<std::mutex> _lock(mLock);

    if( mHandlers.find(handlerID) == mHandlers.end() ){
        return;
    }

    HandlerInfo &info = mHandlers[handlerID];

    std::shared_ptr<AHandler> handler = info.mHandler.lock();

    if (handler != nullptr) {
        handler->resetID();
    }

    info.mHandler.reset();
    info.mLooper.reset();

    mHandlers.erase(handlerID);
}

void ALooperRoster::unregisterStaleHandlers() {

    std::vector<std::shared_ptr<ALooper>> activeLoopers;
    {
        std::lock_guard<std::mutex> _lock(mLock);

        for (int32_t i = mHandlers.size(); i > 0;) {
            i--;
            const HandlerInfo &info = mHandlers[i];

            std::shared_ptr<ALooper> looper = info.mLooper.lock();
            if (looper != nullptr) {
                mHandlers.erase(i);
            } else {
                // At this point 'looper' might be the only std::shared_ptr<> keeping
                // the object alive. To prevent it from going out of scope
                // and having ~ALooper call this method again recursively
                // and then deadlocking because of the Autolock above, add
                // it to a Vector which will go out of scope after the lock
                // has been released.
                activeLoopers.push_back(looper);
            }
        }
    }
}